﻿using Company.Core.Helpers;
using Company.Hardware.Base.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Company.Hardware.Base.Helpers
{
    public class DecoderHelper
    {
        /// <summary>
        /// HL7协议的解码
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static HL7 DecodeHL7(string content)
        {
            HL7 result = new HL7(); 
            try
            {
                //源码
                SourceEntity sourceEntity = new SourceEntity();
                sourceEntity.Data= content;
                result.Source= sourceEntity;

                //处理HL7原始数据没有换行增加换行
                if (content.Contains("\v"))
                {
                    content = content.Replace("\v", "");
                }
                if (content.Contains("\u001c"))
                {
                    content = content.Replace("\u001c", "");
                }
                if (content.Contains("\r\n"))
                {
                    content = content.Replace("\r\n", "");
                }
                if(content.Contains("\n"))
                {
                    content = content.Replace("\n", "");
                }
                if(content.Contains("\r"))
                {
                    content = content.Replace("\r", "");
                }
                content = content.Replace("PID", "\r\nPID");
                content = content.Replace("OBR", "\r\nOBR");
                content = content.Replace("OBX", "\r\nOBX");

                //Get MSH
                string msh = GetHead(content,"MSH");
                result.HL7MSH = GetMSHEntity(msh);

                //Get PID
                string pid = GetHead(content,"PID");
                result.HL7PID = GetPIDEntity(pid);

                //get OBR
                string obr = GetHead(content,"OBR");
                result.HL7OBR = GetOBREntity(obr);

                //get OBX list
                List<string> list = GetOBXList(content);
                result.HL7OBXList = GetOBXEntityList(list);

            }
            catch (Exception ex)
            {
                Logs.Error(ex);
            }

            return result;
        }

        private static List<HL7OBX>? GetOBXEntityList(List<string> list)
        {
            List<HL7OBX> entities = new List<HL7OBX>();
            try
            {
                foreach (var content in list)
                {
                    string[] strings = content.Split('|');
                    HL7OBX entity = new HL7OBX();
                    entities.Add(entity);
                    entity.setId = strings[1];
                    entity.valueType = strings[2];
                    entity.observationIdentifier = strings[3];
                    entity.observationSubId = strings[4];
                    entity.observationValue = strings[5];
                    entity.units = strings[6];
                    entity.referencesRange = strings[7];
                    entity.abnormalFlags = strings[8];
                    entity.probability = strings[9];
                    entity.natureofAbnormalTest = strings[10];
                    entity.observeResultStatus = strings[11];
                    entity.dateLastObserveNormalValues = getDatetime(strings[12]);
                    entity.userDefinedAccessChecks = strings[13];
                    entity.dateTimeoftheObservation = getDatetime(strings[14]);
                    entity.producersID = strings[15];
                    entity.responsibleObserver = strings[16];
                    entity.observationMethod = strings[17];
                }
            }
            catch(Exception ex)
            {
                Logs.Error(ex);
            }

            return entities;
        }

        private static List<string> GetOBXList(string content)
        {
            List<string> result = new List<string>();
            string[] strings = content.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in strings)
            {
                if (item.Length >= 3 && item.Substring(0, 3) == "OBX")
                {
                    result.Add(item);
                }
            }
            return result;
        }

        private static HL7OBR? GetOBREntity(string obr)
        {
            HL7OBR entity = new();
            string[] strings = obr.Split('|');
            try
            {
                entity.setID = strings[1];
                entity.placerOrderNumber= strings[2];
                entity.fillerOrderNumber = strings[3];
                entity.universalServiceID = strings[4];
                entity.priority = strings[5];
                if (string.IsNullOrEmpty(strings[6]) && !string.IsNullOrEmpty(strings[7]))
                {
                    entity.requestedDatetime = getDatetime(strings[7]);
                }
                else
                {
                    entity.requestedDatetime = getDatetime(strings[6]);
                }
                entity.observationDateTime = getDatetime(strings[7]);
                entity.observationEndDateTime = getDatetime(strings[8]);
                entity.collectionVolume = strings[9];
                entity.collectorIdentifier = strings[10];
                entity.specimenActionCode = strings[11];
                entity.dangerCode = strings[12];
                entity.relevantClinicalInfo = strings[13];
                entity.specimenReceivedDateTime = getDatetime(strings[14]);

                entity.specimenSource = strings[15];
                entity.orderingProvider = strings[16];
                entity.orderCallbackPhoneNumber = strings[17];
                entity.placerField1 = strings[18];
                entity.placerField2 = strings[19];
                entity.fillerField1 = strings[20];
                entity.fillerField2 = strings[21];
                entity.resultRptStatusChangeDateTime = getDatetime(strings[22]);

                entity.chargetoPractice = strings[23];
                entity.diagnosticServSectID = strings[24];
                entity.resultStatus = strings[25];
                entity.parentResult = strings[26];
                entity.quantityTiming = strings[27];
                entity.resultCopiesTo = strings[28];
                entity.parent = strings[29];
                entity.transportationMode = strings[30];
                entity.reasonforStudy = strings[31];
                entity.principalResultInterpreter = strings[32];
                entity.assistantResultInterpreter = strings[33];
                entity.technician = strings[34];
                entity.transcriptionist = strings[35];
                entity.scheduledDateTime = getDatetime(strings[36]);

                entity.numberofSampleContainers = strings[37];
                entity.transportLogisticsofCollectedSample = strings[38];
                entity.collectorsComment = strings[39];
                entity.transportArrangementResponsibility = strings[40];
                entity.transportArranged = strings[41];
                entity.escortRequired = strings[42];
                entity.plannedPatientTransportComment = strings[43];
                entity.orderingFacilityName = strings[44];
                entity.orderingFacilityAddress = strings[45];
                if (strings.Length > 46)
                {
                    entity.orderingFacilityPhoneNumber = strings[46];
                }
                else
                {
                    entity.orderingFacilityPhoneNumber = string.Empty;
                }
                if (strings.Length > 47)
                {
                    entity.orderingProviderAddress = strings[47];
                }
                else
                {
                    entity.orderingProviderAddress = string.Empty;
                }
            }
            catch (Exception ex)
            {
                Logs.Error(ex);
            }

            return entity;
        }

        private static HL7PID? GetPIDEntity(string pid)
        {
            HL7PID entity = new();
            string[] strings = pid.Split('|');
            try
            {
                entity.setID = strings[1];
                entity.patientID = strings[2];
                entity.patientIdentifierList = strings[3];
                entity.alternatePatientID = strings[4];
                entity.patientName = strings[5];
                entity.mothersMaidenName = strings[6];
                if (strings[7].Contains("-") && strings[7].Contains(":"))
                {
                    strings[7] = strings[7].Replace("-", "");
                    strings[7] = strings[7].Replace(":", "");
                }
                entity.dateTimeofBirth = getDatetime(strings[7]);
                entity.sex = strings[8];
                entity.patientAlias = strings[9];
                entity.race = strings[10];
                entity.patientAddress = strings[11];
                entity.countyCode = strings[12];
                entity.phoneNumberHome = strings[13];
                entity.phoneNumberBusiness = strings[14];
                entity.primaryLanguage = strings[15];
                entity.maritalStatus = strings[16];
                entity.religion = strings[17];
                entity.patientAccountNumber = strings[18];
                entity.sSNNumberPatient = strings[19];
                entity.driversLicenseNumberPatient = strings[20];
                entity.mothersIdentifier = strings[21];
                entity.ethnicGroup = strings[22];
                entity.birthPlace = strings[23];
                entity.multipleBirthIndicator = strings[24];
                entity.birthOrder = strings[25];
                entity.citizenship = strings[26];
                entity.veteransMilitaryStatus = strings[27];
                entity.nationality = strings[28];
                entity.patientDeathDateandTime = getDatetime(strings[29]);
                entity.patientDeathIndicator = strings[30];
            }
            catch(Exception ex)
            {
                Logs.Error(ex);
            }
            
            return entity;
        }

       

        private static string GetHead(string content,string name)
        {
            string[] strings = content.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in strings)
            {
                if (s.Length >= 3 && s.Substring(0, 3) == name)
                {
                    return s;
                }
            }
            return string.Empty;
        }

        private static HL7MSH GetMSHEntity(string msh)
        {
            HL7MSH entity = new HL7MSH();
            string[] strings = msh.Split('|');
            try
            {
                entity.fieldSeparator = strings[0];
                entity.encodingCharacters = strings[1];
                entity.sendingApplication= strings[2];
                entity.sendingFacility = strings[3];
                entity.receivingApplication = strings[4];
                entity.receivingFacility = strings[5];
                entity.dateTimeOfMessage = getDatetime(strings[6]);
                entity.security = strings[7];
                entity.messageType = strings[8];
                entity.messageControlID = strings[9];
                entity.processingID = strings[10];
                entity.versionID = strings[11];
                entity.sequenceNumber = strings[12];
                entity.continuationPointer = strings[13];
                entity.acceptAcknowledgmentType = strings[14];
                entity.applicationAcknowledgmentType = strings[15];
                entity.countryCode = strings[16];
                entity.characterSet = strings[17];
                entity.principalLanguageOfMessage = strings[18];
                entity.alternateCharacterSetHandlingScheme = strings[19];
            }
            catch(Exception ex)
            {
                Logs.Error(ex);
            }
            return entity;
        }

        private static DateTime getDatetime(string v)
        {
            //20240809153529  ->  "2024/08/09 15:32:55"
            if(string.IsNullOrEmpty(v)||v.Length!=14)
            {
                return DateTime.MinValue; 
            }
            string temp = $"{v.Substring(0,4)}/{v.Substring(4,2)}/{v.Substring(6,2)} {v.Substring(8,2)}:{v.Substring(10,2)}:{v.Substring(12,2)}";//得到格式
            if(DateTime.TryParse(temp,out DateTime date))
            {
                return date;
            }
            return DateTime.MinValue;

        }
    }
}
